/********************************************************************************
* @file    bsp_adc.c
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-07-06
* @brief   NRF51系列，ADC设计讲解
10位ADC，内部选择1/3输入， ADC基准使用自带1.2V。  最大测量范围 0~1.2*3=3.6V，

!!!引脚输入电压不允许超过2.4*3=7.2V   且规则2 !!!

限制规则：
    1，引脚上的输入电压经过缩放后不能大于2.4V，
    2, GPIO上的输入电压不能超过VDD+0.3V.

一般锂电池都是4.2V左右，上面最大测量范围不符合，我们需要在外部电压设计一个1/2电路。
4.2V/2=2.1V，这样就能符合条件。
计算公式： ((ADC_VAL*1.2V)*3/1023.0)*2
3--内部输入比例
2--外部输入比例
********************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "RTE_Components.h"
#include CMSIS_device_header

#include "nrf_adc.h"
#include "nrf_drv_adc.h"
#include "sdk_errors.h"

#include "bsp_gpio.h"
#include "bsp_exti.h"
#include "bsp_adc.h"

/* Private Includes ----------------------------------------------------------*/
#include "ls_gpio.h"
#include "ls_syscfg.h"

/* Private Define ------------------------------------------------------------*/
#define ADC0_CH_NUM                   8

#define ADC0_CH0                      0
#define ADC0_CH1                      1
#define ADC0_CH2                      2
#define ADC0_CH3                      3
#define ADC0_CH4                      4
#define ADC0_CH5                      5
#define ADC0_CH6                      6
#define ADC0_CH7                      7


#define CH_NUM  (BS_ADC0_CH0 + BS_ADC0_CH1 + BS_ADC0_CH2 + BS_ADC0_CH3 + BS_ADC0_CH4 + BS_ADC0_CH5 + BS_ADC0_CH6 + BS_ADC0_CH7)
/* Private Variables ---------------------------------------------------------*/
#if BS_ADC0_EN
// ADC初始化状态(0--deinit 1--init)
static bool g_adc_init = false;
// ADC采集数据存储buff
uint16_t bsp_adc0_val[ADC0_CH_NUM] = {0};
uint16_t bsp_adc0_temp_val[CH_NUM] = {0};
// 定义ADC采集完毕回调函数
typedef void(*bsp_adc0_callback)(void);
static bsp_adc0_callback irq_callback;
#endif
/****************结构体定义****************/
#if CH_NUM > 0 && BS_ADC0_EN
nrf_drv_adc_config_t nrf_adc_config = NRF_DRV_ADC_DEFAULT_CONFIG;

/**< Channel instance. Default configuration used. */
#if BS_ADC0_CH0
    static nrf_drv_adc_channel_t m_channel0_config = {{{.resolution = NRF_ADC_CONFIG_RES_10BIT,
                                                        .input = NRF_ADC_CONFIG_SCALING_INPUT_ONE_THIRD,
                                                        .reference = NRF_ADC_CONFIG_REF_VBG,
                                                        .ain = (NRF_ADC_CONFIG_INPUT_0)}},
                                                      NULL};
#endif
#if BS_ADC0_CH1
    static nrf_drv_adc_channel_t m_channel1_config = {{{.resolution = NRF_ADC_CONFIG_RES_10BIT,
                                                        .input = NRF_ADC_CONFIG_SCALING_INPUT_ONE_THIRD,
                                                        .reference = NRF_ADC_CONFIG_REF_VBG,
                                                        .ain = (NRF_ADC_CONFIG_INPUT_1)}},
                                                      NULL};
#endif
#if BS_ADC0_CH2
    static nrf_drv_adc_channel_t m_channel2_config = {{{.resolution = NRF_ADC_CONFIG_RES_10BIT,
                                                        .input = NRF_ADC_CONFIG_SCALING_INPUT_ONE_THIRD,
                                                        .reference = NRF_ADC_CONFIG_REF_VBG,
                                                        .ain = (NRF_ADC_CONFIG_INPUT_2)}},
                                                      NULL};
#endif
#if BS_ADC0_CH3
    static nrf_drv_adc_channel_t m_channel3_config = {{{.resolution = NRF_ADC_CONFIG_RES_10BIT,
                                                        .input = NRF_ADC_CONFIG_SCALING_INPUT_ONE_THIRD,
                                                        .reference = NRF_ADC_CONFIG_REF_VBG,
                                                        .ain = (NRF_ADC_CONFIG_INPUT_3)}},
                                                      NULL};
#endif
#if BS_ADC0_CH4
    static nrf_drv_adc_channel_t m_channel4_config = {{{.resolution = NRF_ADC_CONFIG_RES_10BIT,
                                                        .input = NRF_ADC_CONFIG_SCALING_INPUT_ONE_THIRD,
                                                        .reference = NRF_ADC_CONFIG_REF_VBG,
                                                        .ain = (NRF_ADC_CONFIG_INPUT_4)}},
                                                      NULL};
#endif
#if BS_ADC0_CH5
    static nrf_drv_adc_channel_t m_channel5_config = {{{.resolution = NRF_ADC_CONFIG_RES_10BIT,
                                                        .input = NRF_ADC_CONFIG_SCALING_INPUT_ONE_THIRD,
                                                        .reference = NRF_ADC_CONFIG_REF_VBG,
                                                        .ain = (NRF_ADC_CONFIG_INPUT_5)}},
                                                      NULL};
#endif
#if BS_ADC0_CH6
    static nrf_drv_adc_channel_t m_channel6_config = {{{.resolution = NRF_ADC_CONFIG_RES_10BIT,
                                                        .input = NRF_ADC_CONFIG_SCALING_INPUT_ONE_THIRD,
                                                        .reference = NRF_ADC_CONFIG_REF_VBG,
                                                        .ain = (NRF_ADC_CONFIG_INPUT_6)}},
                                                      NULL};
#endif
#if BS_ADC0_CH7
    static nrf_drv_adc_channel_t m_channel7_config = {{{.resolution = NRF_ADC_CONFIG_RES_10BIT,
                                                        .input = NRF_ADC_CONFIG_SCALING_INPUT_ONE_THIRD,
                                                        .reference = NRF_ADC_CONFIG_REF_VBG,
                                                        .ain = (NRF_ADC_CONFIG_INPUT_7)}},
                                                      NULL};
#endif
#endif

/* External Variables --------------------------------------------------------*/
/* Private Function Prototypes -----------------------------------------------*/
#if BS_ADC0_EN
/**
 * @brief  将ADC采集的值重新排序到另一个数组
 * @note   NULL
 * @retval None
 */
static void bsp_adc0_val_copy(void)
{
    uint8_t num = 0;
    bool flag = false;

    for (uint8_t i = 0; i < ADC0_CH_NUM; i++)
    {
        if (i == ADC0_CH0 && BS_ADC0_CH0)
        {
            flag = true;
        }
        else if(i == ADC0_CH1 && BS_ADC0_CH1)
        {
            flag = true;
        }
        else if(i == ADC0_CH2 && BS_ADC0_CH2)
        {
            flag = true;
        }
        else if(i == ADC0_CH3 && BS_ADC0_CH3)
        {
            flag = true;
        }
        else if(i == ADC0_CH4 && BS_ADC0_CH4)
        {
            flag = true;
        }
        else if(i == ADC0_CH5 && BS_ADC0_CH5)
        {
            flag = true;
        }
        else if(i == ADC0_CH6 && BS_ADC0_CH6)
        {
            flag = true;
        }
        else if(i == ADC0_CH7 && BS_ADC0_CH7)
        {
            flag = true;
        }
        if (flag)
        {
            flag = false;
            // ADC内部1/3输入
            bsp_adc0_val[i] = bsp_adc0_temp_val[num]*3;
            num++;
            if (num == CH_NUM)
            {
                break;
            }
        }
    }
}

/**
 * @brief ADC interrupt handler.
 */
static void adc_event_handler(nrf_drv_adc_evt_t const * p_event)
{
    if (p_event->type == NRF_DRV_ADC_EVT_DONE)
    {
        bsp_adc0_val_copy();
        nrf_drv_adc_buffer_convert(p_event->data.done.p_buffer, CH_NUM);
        if (irq_callback)
        {
            irq_callback();
        }
    }
}

/* Public Function Prototypes ------------------------------------------------*/
/**
 * @brief  ADC0初始化，并使能通道
 */
void bsp_adc0_init(void)
{
#if CH_NUM > 0
    if (g_adc_init)
    {
        return;
    }
    APP_ERROR_CHECK(nrf_drv_adc_init(&nrf_adc_config, adc_event_handler));
#if BS_ADC0_CH0
    nrf_drv_adc_channel_enable(&m_channel0_config);
#endif
#if BS_ADC0_CH1
    nrf_drv_adc_channel_enable(&m_channel1_config);
#endif
#if BS_ADC0_CH2
    nrf_drv_adc_channel_enable(&m_channel2_config);
#endif
#if BS_ADC0_CH3
    nrf_drv_adc_channel_enable(&m_channel3_config);
#endif
#if BS_ADC0_CH4
    nrf_drv_adc_channel_enable(&m_channel4_config);
#endif
#if BS_ADC0_CH5
    nrf_drv_adc_channel_enable(&m_channel5_config);
#endif
#if BS_ADC0_CH6
    nrf_drv_adc_channel_enable(&m_channel6_config);
#endif
#if BS_ADC0_CH7
    nrf_drv_adc_channel_enable(&m_channel7_config);
#endif
    nrf_drv_adc_buffer_convert((nrf_adc_value_t *)bsp_adc0_temp_val, CH_NUM);
    g_adc_init = true;
#endif
}

/**
 * @brief  ADC0功能关闭，并移除
 */
void bsp_adc0_deinit(void)
{
#if CH_NUM > 0
    if (!g_adc_init)
    {
        return;
    }
#if BS_ADC0_CH0
    nrf_drv_adc_channel_disable(&m_channel0_config);
#endif
#if BS_ADC0_CH1
    nrf_drv_adc_channel_disable(&m_channel1_config);
#endif
#if BS_ADC0_CH2
    nrf_drv_adc_channel_disable(&m_channel2_config);
#endif
#if BS_ADC0_CH3
    nrf_drv_adc_channel_disable(&m_channel3_config);
#endif
#if BS_ADC0_CH4
    nrf_drv_adc_channel_disable(&m_channel4_config);
#endif
#if BS_ADC0_CH5
    nrf_drv_adc_channel_disable(&m_channel5_config);
#endif
#if BS_ADC0_CH6
    nrf_drv_adc_channel_disable(&m_channel6_config);
#endif
#if BS_ADC0_CH7
    nrf_drv_adc_channel_disable(&m_channel7_config);
#endif
    nrf_drv_adc_uninit();
    g_adc_init = false;
#endif
}

/**
 * @brief  ADC0 启动采样功能
 */
void bsp_adc0_start(void)
{
#if CH_NUM
    if (!g_adc_init)
    {
        return;
    }
    if (!nrf_adc_is_busy())
    {
        nrf_drv_adc_sample();
    }
#endif
}
/**
 * @brief  得到ADC0采样值
 * @param  ch_num: 通道值
 * @retval 通道对应的ADC值
 */
uint16_t bsp_adc0_get_ch_val(uint8_t ch_num)
{
    if (ch_num >= ADC0_CH_NUM)
    {
        return 0xFFFF;
    }
    return bsp_adc0_val[ch_num];
}

/**
 * @brief  注册ADC0采样完毕回调函数
 * @param  *event: 绑定回调事件
 * @retval 0--失败 1--成功
 */
bool bsp_adc0_irq_callback(void *event)
{
    if (irq_callback != NULL)
    {
        return false;
    }
    else
    {
        irq_callback = (bsp_adc0_callback)event;
    }
    return true;
}

#else
void bsp_adc0_init(void)
{
}

void bsp_adc0_deinit(void)
{
}

void bsp_adc0_start(void)
{
}

uint16_t bsp_adc0_get_ch_val(uint8_t ch_num)
{
    return 0;
}

bool bsp_adc0_irq_callback(void *event)
{
    return false;
}
#endif


